#include <iostream>
#include <string>;
using namespace std;

//Project demonstrating a really bad practice :)
//Project also contains some experimentation code


template<class T>
void Swap(T & v1, T & v2){
	T temp;
	temp = v1;
	v1=v2;
	v2=temp;
}

class SuchAHiddenClass{
private:
	//Don't access my stuff! It's private!
	int x,y,z;
	string *namn;

	//Except you, you are my friend
	friend class FriendlyClass;
public:
	SuchAHiddenClass(){
		x=1;
		y=2;
		z=3;
		namn=new string("Simon");
	}

	~SuchAHiddenClass(){
		delete namn;
	}
};

class FriendlyClass{

public:
	void PrintPrivate(SuchAHiddenClass & otherClass){
		cout << "Friendly x: " << otherClass.x << endl;
		cout << "Friendly y: " << otherClass.y << endl;
		cout << "Friendly z: " << otherClass.z << endl;
		cout << "Friendly namn: " << *otherClass.namn << endl;
	}
};

//Structure of the private fields
typedef struct PrivateFields_t{
	int x,y,z;
	string* namn;
} PrivateFields;


string* intToString(int number, int base){
	char* symbols = "0123456789ABCDEF";
	string temp;
	while(number>1){
		temp.push_back(symbols[number%base]);
		number/=base;
	}
	string* result = new string(temp.rbegin(),temp.rend());
	return result;
}

typedef unsigned char uint8_t;
int main(){
	
	//Testing int to string conversion
	string* str = intToString(0xFF0033,16);
	cout << *str << endl;
	delete(str);

	SuchAHiddenClass mittObjekt;
	//mittObjekt.x doesn't work. It shouldn't work either.
	
	//Get a byte pointer to the object
	uint8_t* objectBytePointer = (uint8_t*)&mittObjekt;

	//Naughty getters
	cout << "x: " << *(int*)(objectBytePointer+(sizeof(int)*0)) << endl;
	cout << "y: " << *(int*)(objectBytePointer+(sizeof(int)*1)) << endl;
	cout << "z: " << *(int*)(objectBytePointer+(sizeof(int)*2)) << endl;

	cout << "namn: " << **(string**)(objectBytePointer+(sizeof(int)*3)) << endl; //Dereference the dereferenced pointer to a pointer :)

	//Naughty setter
    cout << "set z=7" << endl;
	objectBytePointer[sizeof(int)*2]=7;
	
	//Second naughty getter
	cout << "z: " << (int)objectBytePointer[sizeof(int)*2] << endl;
	cout << endl;
	
	//Prettier, but still naughty behaviour
	PrivateFields* privateFields = (PrivateFields*)&mittObjekt;
	cout << "x: " << privateFields->x << endl;
	cout << "y: " << privateFields->y << endl;
	cout << "z: " << privateFields->z << endl;
	cout << "namn: " << *privateFields->namn << endl << endl;

	
	//Nooo, you've done bad things!!

	//Better way of doing it
	FriendlyClass friendly;
	friendly.PrintPrivate(mittObjekt);
	system("pause");


	//Template swapping test
	int x=5, y=10;
	Swap(x,y);
	cout << x << endl;
	cout << y << endl;
	system("pause");

	return 0;
}